﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using ESRI.ArcGIS.ArcMapUI;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.DataSourcesRaster;
using ESRI.ArcGIS.Geodatabase;

namespace ODM_Code.Forms
{
    public partial class ComparisonForm : Form
    {

        private string dbfPath = null;
        private string inputPath = null;
        private ODM_Code.rUtils ru;
        private esriUtil.rasterUtil eru;

        private IMap map;
        private IActiveView view;

        private Dictionary<string, IRaster> rasList = new Dictionary<string, IRaster>();

        public ComparisonForm()
        {
            InitializeComponent();
        }

        public ComparisonForm(IMxDocument pMxDoc)
        {
            InitializeComponent();

            dbfPath = "C:\\magfire\\" + ConfigSettings.ReadSetting("analysisArea");
            inputPath = "C:\\magfire\\" + ConfigSettings.ReadSetting("analysisArea") + "\\input";

            ru = new ODM_Code.rUtils();
            eru = new esriUtil.rasterUtil();
            IMxDocument doc = pMxDoc;
            map = doc.FocusMap;
            view = doc.ActiveView;

            map.SpatialReference = ru.GetAlbersProjection();
        }

        public void ComparisonForm_Load(object sender, EventArgs e)
        {
            string[] files = System.IO.Directory.GetDirectories(inputPath);
            foreach (string s in files)
            {
                string[] spl = s.Split('\\');
                int i = spl.Length;

                string addThis = spl[i - 1];

                if (addThis.StartsWith("S"))
                {
                    this.altComBox1.Items.Add(spl[i - 1]);
                    this.altComBox2.Items.Add(spl[i - 1]);
                    this.sd_altComBox1.Items.Add(spl[i - 1]);
                    this.sd_altComBox2.Items.Add(spl[i - 1]);
                    this.nflrAlternativeBox.Items.Add(spl[i - 1]);
                }
            }
        }

        private void checkCmp_CheckChanged(object sender, EventArgs e)
        {
            if (checkCmp.Checked)
            {
                checkCmpAt.Checked = true;
                checkCmpEl.Checked = true;
                checkCmpFl.Checked = true;
                checkCmpBin.Checked = true;
            }
            else
            {
                checkCmpAt.Checked = false;
                checkCmpEl.Checked = false;
                checkCmpFl.Checked = false;
                checkCmpBin.Checked = false;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (tabControl1.SelectedTab.Equals(tabPageCross))
            {
                this.button1_Click_CrossAlternative(sender, e);
            }
            else if (tabControl1.SelectedTab.Equals(tabPageCheckProj))
            {
                this.button1_Click_CheckProject(sender, e);
            }
            else if (tabControl1.SelectedTab.Equals(tabPageFlameLength))
            {
                this.button1_Click_NodeFlamelength(sender, e);
            }
        }

        private Boolean missingUserInput()
        {
            bool missingInput = true;

            if (!altComBox1.Text.Equals("") && !altComBox2.Text.Equals(""))
            {
                if (!fireBox1.Text.Equals("") && !fireBox2.Text.Equals(""))
                {
                    if (!periodBox1.Text.Equals("") && !periodBox2.Text.Equals(""))
                    {
                        if ((useBestSol1.Checked || !iterationBox1.Text.Equals("")) && (useBestSol2.Checked || !iterationBox2.Text.Equals("")))
                        {
                            missingInput = false;
                        }
                        else
                        {
                            MessageBox.Show("You must enter an iteration or check \"Use Best Solution\"", "Comparison Input Error");
                        }
                    }
                    else
                    {
                        MessageBox.Show("You must input a valid period.", "Comparison Input Error");
                    }
                }
                else
                {
                    MessageBox.Show("You must input a fire number.", "Comparison Input Error");
                }

            }
            else
            {
                MessageBox.Show("You must select an alternative for both selections.", "Comparison Input Error"); 
            }
            
            return missingInput;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="resultsFolder">Path to results folder</param>
        /// <param name="alternative">Alternative 1 or 2</param>
        /// <returns></returns>
        private Boolean checkUserInput(string resultsFolder, int alternative)
        {
            //bool goodInput = false;

            //int fire = 0;
            string fireNum;
            if (alternative == 1)
            {
                
                fireNum = fireBox1.Text; 
            }
            if (alternative == 2)
            {
                fireNum = fireBox2.Text;
            }

            int period1 = int.Parse(periodBox1.Text);
            int period2 = int.Parse(periodBox2.Text);

            return true;
        }

        private void button1_Click_CrossAlternative(object sender, EventArgs e)
        {
            // Set up strings and paths
            string resultsPath1 = inputPath + "\\" + altComBox1.Text + "\\results";
            string resultsPath2 = inputPath + "\\" + altComBox2.Text + "\\results";
            string gisPath1 = inputPath + "\\" + altComBox1.Text + "\\results\\gis\\";
            string gisPath2 = inputPath + "\\" + altComBox2.Text + "\\results\\gis\\";

            string dllPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

            // Clear the temp directory
            ru.ClearTemp();

            // Check user inputs, and break execution if necessary
            if (this.missingUserInput())
            {
                return;
            }
            if (this.checkUserInput(resultsPath1, 1) == false)
            {
                return;
            }
            if (this.checkUserInput(resultsPath2, 2) == false)
            {
                return;
            }

            int bestSol1 = 0;
            int bestSol2 = 0;

            if (useBestSol1.Checked)
            {
                bestSol1 = ru.GetBestSolutionNum(resultsPath1);
            }
            else
            {
                bestSol1 = int.Parse(iterationBox1.Text);
            }

            if (useBestSol2.Checked)
            {
                bestSol2 = ru.GetBestSolutionNum(resultsPath2);
            }
            else
            {
                bestSol2 = int.Parse(iterationBox2.Text);
            }


            MessageBox.Show(bestSol1.ToString() + " | " + bestSol2.ToString(), "Solution Values");

            // Check if the "Clear Map" checkbox has been checked, and clear the map if so.
            if (clearLayers.Checked)
            {
                map.ClearLayers();
                view.Refresh();
                view.ContentsChanged();
            }

            string rasName1 = null;
            string rasName2 = null;
            string compName = null;
            string binName = null;
            string layerRender = null;
            string binaryRender = null;
            IRaster ras1 = null;
            IRaster ras2 = null;
            IRaster compRas = null;

            List<CheckBox> checkList = new List<CheckBox> { checkCmpAt, checkCmpEl, checkCmpFl };

            foreach (CheckBox box in checkList)
            {
                if (!box.Checked)
                {
                    continue;
                }

                switch (box.Text)
                {
                    case "Arrival Time":
                        rasName1 = gisPath1 + "arrivaltime" + bestSol1.ToString() + "_" + fireBox1.Text + "_" + periodBox1.Text + ".tif";
                        rasName2 = gisPath2 + "arrivaltime" + bestSol2.ToString() + "_" + fireBox2.Text + "_" + periodBox2.Text + ".tif";
                        compName = "Arrival Time Comparison";
                        binName = "Arrival Time Binary Comparison";
                        layerRender = dllPath + "\\res\\at_class.lyr";
                        binaryRender = dllPath + "\\res\\bincomp.lyr";
                        break;
                    case "Node Flamelength":
                        rasName1 = gisPath1 + "nodeflamelength" + bestSol1.ToString() + "_" + fireBox1.Text + "_" + periodBox1.Text + ".tif";
                        rasName2 = gisPath2 + "nodeflamelength" + bestSol2.ToString() + "_" + fireBox2.Text + "_" + periodBox2.Text + ".tif";
                        compName = "Node Flamelength Comparison";
                        binName = "Node Flamelength Binary Comparison";
                        layerRender = dllPath + "\\res\\fl_class.lyr";
                        binaryRender = dllPath + "\\res\\bincomp2.lyr";
                        break;
                    case "Expected Loss":
                        rasName1 = gisPath1 + "objvalues" + bestSol1.ToString() + "_" + fireBox1.Text + "_" + periodBox1.Text + ".tif";
                        rasName2 = gisPath2 + "objvalues" + bestSol2.ToString() + "_" + fireBox2.Text + "_" + periodBox2.Text + ".tif";
                        compName = "Expected Loss Comparison";
                        binName = "Expected Loss Binary Comparison";
                        layerRender = dllPath + "\\res\\el_class.lyr";
                        binaryRender = dllPath + "\\res\\bincomp2.lyr";
                        break;
                }

                if (!File.Exists(rasName1))
                {
                    MessageBox.Show(rasName1 + " does not exist.\nCreate the raster by using the \"Add OptFuels Data\" tool first.", "Raster Load Error");
                    return;
                }
                else
                {
                    ras1 = eru.returnRaster(rasName1);
                }

                if (!File.Exists(rasName2))
                {
                    MessageBox.Show(rasName2 + " does not exist.\nCreate the raster by using the \"Add OptFuels Data\" tool first.", "Raster Load Error");
                    return;
                }
                else
                {
                    ras2 = eru.returnRaster(rasName2);
                }

                // Perform the calculation
                try
                {
                    compRas = eru.calcArithmaticFunction(ras1, ras2, esriRasterArithmeticOperation.esriRasterMinus);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Comparison Calculation Error");
                    System.Diagnostics.Trace.WriteLine(ex.Message, "Minus Function");
                }

                // Calculate statistics
                compRas = eru.calcStatsAndHist(compRas);
                eru.buildVat(compRas);

                compRas = eru.calcRemapFunction(compRas, ru.GetArrivalTimeClasses());

                // Add layer to map
                IRasterLayer irl = new RasterLayerClass();
                irl.CreateFromRaster(compRas);
                irl.Name = compName;
                if (this.useRenderers.Checked)
                {
                    irl.Renderer = ru.ImportRasterRenderer(layerRender);
                }

                ILegendInfo lInfo = (ILegendInfo)irl;
                lInfo.get_LegendGroup(0).Visible = false;

                map.AddLayer(irl);

                if (checkCmpBin.Checked)
                {
                    compRas = eru.calcRemapFunction(compRas, ru.GetFilterForBinary());

                    compRas = eru.calcStatsAndHist(compRas);
                    eru.buildVat(compRas);

                    irl = new RasterLayerClass();
                    irl.CreateFromRaster(compRas);
                    irl.Name = binName;
                    if (this.useRenderers.Checked)
                    {
                        irl.Renderer = ru.ImportRasterRenderer(binaryRender);
                    }

                    ILegendInfo lInfo2 = (ILegendInfo)irl;
                    lInfo2.get_LegendGroup(0).Visible = false;

                    map.AddLayer(irl);
                }
            }

            view.Refresh();
            view.ContentsChanged();
            MessageBox.Show("Selected data added to map.", "OptFuels Comparison Tool");
            this.Close();
        }

        private void button1_Click_CheckProject(object sender, EventArgs e)
        {
            // Set up strings and paths
            string resultsPath1 = inputPath + "\\" + sd_altComBox1.Text + "\\results";
            string resultsPath2 = inputPath + "\\" + sd_altComBox2.Text + "\\results";
            string treatgridPath = inputPath + "\\" + sd_altComBox1.Text + "\\treatgrid.txt";
            string treatshapePath = inputPath + "\\" + sd_altComBox1.Text + "\\treat.shp";

            Code.CheckProjectNAvTR cpnvt = new Code.CheckProjectNAvTR(resultsPath1, resultsPath2, treatgridPath);
            cpnvt.setTreatShapePath(treatshapePath);
            cpnvt.setFire1(sd_fireBox1.Text);
            cpnvt.setPeriod1(sd_perBox1.Text);
            cpnvt.setIter1(sd_iterBox1.Text);
            cpnvt.setFire2(sd_fireBox2.Text);
            cpnvt.setPeriod2(sd_perBox2.Text);
            cpnvt.setIter2(sd_iterBox2.Text);
            cpnvt.setUseTreated(sd_checkTreatedOnly.Checked);

            Dictionary<string, double[]> ret = cpnvt.CompareRasters();
            tbATSum.Text = rUtils.RoundDoubleForView((ret["arrivaltime"])[0]);
            tbATMean.Text = rUtils.RoundDoubleForView((ret["arrivaltime"])[1]);
            tbFLSum.Text = rUtils.RoundDoubleForView((ret["nodeflamelength"])[0]);
            tbFLMean.Text = rUtils.RoundDoubleForView((ret["nodeflamelength"])[1]);
            tbOVSum.Text = rUtils.RoundDoubleForView((ret["objvalues"])[0]);
            tbOVMean.Text = rUtils.RoundDoubleForView((ret["objvalues"])[1]);

            label29.Text = "n = " + (ret["arrivaltime"])[2].ToString();

            cpnvt.RunPairedTTest();
        }

        private void button1_Click_NodeFlamelength(object sender, EventArgs e)
        {
            string nflrResultsPath = inputPath + "\\" + nflrAlternativeBox.Text + "\\results";
            string nflrGisPath = inputPath + "\\" + nflrAlternativeBox.Text + "\\results\\gis\\";

            string dllPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

            // Clear the temp directory
            ru.ClearTemp();

            // Check if the "Clear Map" checkbox has been checked, and clear the map if so.
            if (clearLayers.Checked)
            {
                map.ClearLayers();
                view.Refresh();
                view.ContentsChanged();
            }

            int bestSol = ru.GetBestSolutionNum(nflrResultsPath);

            string treatRasName = nflrGisPath + "nodeflamelength" + bestSol.ToString() + "_" + nflrFireBox.Text + "_" + nflrPeriodBox.Text + ".tif";
            string noactionRasName = nflrGisPath + "nodeflamelength" + "0" + "_" + nflrFireBox.Text + "_" + nflrPeriodBox.Text + ".tif";
            string compName = "Node Flamelength Diff Reclass";            
            float threshold = float.Parse(nflrThresholdBox.Text);

            IRaster treatRas = null;
            IRaster noactionRas = null;
            IRaster compRas = null;
            IRaster tempGreater = null;
            IRaster tempLesser = null;

            if (!File.Exists(treatRasName))
            {
                MessageBox.Show(treatRasName + " does not exist.\nCreate the raster by using the \"Add OptFuels Data\" tool first.", "Raster Load Error");
                return;
            }
            else
            {
                treatRas = eru.returnRaster(treatRasName);
            }

            if (!File.Exists(noactionRasName))
            {
                MessageBox.Show(noactionRasName + " does not exist.\nCreate the raster by using the \"Add OptFuels Data\" tool first.", "Raster Load Error");
                return;
            }
            else
            {
                noactionRas = eru.returnRaster(noactionRasName);
            }

            try
            {
                // Perform the no action greater than threshold calculation
                tempGreater = eru.calcGreaterFunction(noactionRas, threshold);

                // Perform the treatment less than threshold calculation
                tempLesser = eru.calcLessFunction(treatRas, threshold);

                // Set pixels we don't want about to 0
                compRas = eru.calcArithmaticFunction(treatRas, tempGreater, esriRasterArithmeticOperation.esriRasterMultiply);
                compRas = eru.calcArithmaticFunction(compRas, tempLesser, esriRasterArithmeticOperation.esriRasterMultiply);

                // Finally, set all values not already set to 0 to 1
                compRas = eru.calcGreaterFunction(compRas, 0);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Comparison Calculation Error");
                System.Diagnostics.Trace.WriteLine(ex.Message, "No Action Threshold Function");
            }

            // Calculate statistics
            compRas = eru.calcStatsAndHist(compRas);
            eru.buildVat(compRas);

            //compRas = eru.convertToDifFormatFunction(compRas, rstPixelType.PT_UCHAR);

            //IRaster2 compRas2 = (IRaster2)compRas;
            //IRasterDataset compDS = compRas2.RasterDataset;
            //IRasterDatasetEdit2 compEdit2 = (IRasterDatasetEdit2)compDS;

            //try
            //{
            //    compEdit2.BuildAttributeTable();
            //}
            //catch (Exception ex)
            //{
            //    MessageBox.Show(ex.Message, "BuildAttributeTable Fail");
            //    System.Diagnostics.Trace.WriteLine(ex.Message, "NFL_Comp_BuildAttributeTable");
            //}

            // Add layer to map
            IRasterLayer irl = new RasterLayerClass();
            irl.CreateFromRaster(compRas);
            irl.Name = compName;
            map.AddLayer(irl);

            this.Close();
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (tabControl1.SelectedTab.Equals(tabPageFlameLength))
            {
                checkCmpAt.Checked = false;
                checkCmpEl.Checked = false;
                checkCmpFl.Checked = true;
                checkCmpBin.Checked = false;
                checkCmp.Checked = false;

                checkCmpAt.Enabled = false;
                checkCmpEl.Enabled = false;
                checkCmpFl.Enabled = false;
                checkCmpBin.Enabled = false;
                checkCmp.Enabled = false;

                sd_checkTreatedOnly.Visible = false;

                button1.Text = "Add Layers";
            }
            else if (tabControl1.SelectedTab.Equals(tabPageCheckProj))
            {
                checkCmpAt.Checked = true;
                checkCmpEl.Checked = true;
                checkCmpFl.Checked = true;
                checkCmpBin.Checked = false;
                checkCmp.Checked = false;

                checkCmpAt.Enabled = false;
                checkCmpEl.Enabled = false;
                checkCmpFl.Enabled = false;
                checkCmpBin.Enabled = false;
                checkCmp.Enabled = false;

                sd_checkTreatedOnly.Visible = true;

                button1.Text = "Calculate Differences";
            }
            else
            {
                checkCmpAt.Checked = false;
                checkCmpEl.Checked = false;
                checkCmpFl.Checked = false;
                checkCmpBin.Checked = false;
                checkCmp.Checked = false;

                checkCmpAt.Enabled = true;
                checkCmpEl.Enabled = true;
                checkCmpFl.Enabled = true;
                checkCmpBin.Enabled = true;
                checkCmp.Enabled = true;

                sd_checkTreatedOnly.Visible = false;

                button1.Text = "Add Layers";
            }
        } 

    }
}
